/*
 * vim: ts=4 sw=4 ai noet tw=78
 * $Coar$
 */
#ifndef LDAPENTER_EXTERN_H
#define LDAPENTER_EXTERN_H 1

#include <sys/types.h> /* size_t */
#include <sys/queue.h>
#include <stdio.h> /* FILE */
#include <ldap.h>
#include <ldap_schema.h>

/*
 * Schema-parsed object class definitions.
 * We keep the original handle, as there are four fields we need. May as well
 * keep the original intact in case we want to query more information in the
 * future.
 */
typedef struct class_entry
{
	char						*name;
	LDAPObjectClass				*lo;
	SLIST_ENTRY(class_entry)	 next;
} class_entry_t;

typedef struct
{
	SLIST_HEAD(, class_entry)	 head;
	size_t						 cnt;
} class_list_t;

/*
 * Schema-parsed attribute definitions.
 * We only need the name and description and it's quite unlikely we're gonna
 * need more.
 */
typedef struct attr_dfn_entry
{
	char						*name;
	char						*desc;
	SLIST_ENTRY(attr_dfn_entry)  next;
} attr_dfn_entry_t;

typedef struct
{
	SLIST_HEAD(, attr_dfn_entry) head;
	size_t						 cnt;
} attr_dfn_list_t;

/*
 * Our union of attributes as they relate to the requested filter.
 * On each entry this list is cleared to make room for the next entry's
 * values.
 */
typedef struct attr_entry
{
	char					*name;
	size_t					 name_len;
	char					*value;
	size_t					 value_len;
	STAILQ_ENTRY(attr_entry)	 next;
} attr_entry_t;

typedef struct
{
	STAILQ_HEAD(, attr_entry)	head;
	size_t						cnt;
} attr_list_t;
#define LDE_LIST_HEAD(__lst) &((__lst)->head)

/*
 * Main runtime context. These could all be globals. Yet, we hate globals.
 */
struct runtime_
{
	/*
	 * Options
	 */
	char		*opt_conn_dn; // Connection Distinguished Name
	int			 opt_conn_pwprompt; // Connection password prompt?
	int			 opt_compact; // Compact format (no modify directives)
	FILE		*opt_conn_pwfile; // Connection password file
	char		*opt_conn_host; // Connection Host
	char		*opt_conn_uri; // Connection URI
	uint16_t	 opt_conn_port; // Connection port
	char		*opt_conn_sasl_props; // SASL security properties
	char		*opt_conn_sasl_authcid; // SASL authentication ID
	char		*opt_conn_sasl_realm; // SASL authentication realm
	char		*opt_conn_sasl_authzid; // SASL authorization ID
	char		*opt_conn_sasl_mech; // SASL authentication mechanism
	char		*opt_base; // search base
	ber_int_t	 opt_scope; // search scope
	FILE		*opt_file; // output file
	int			 opt_verbose; // verbosity
	int			 opt_tls; // TLS setting
	int			 opt_editmode; // In editmode?
	char		*env_editor;
	/*
	 * Arguments
	 */
	char *arg_entry; // Entry to search for
	char *arg_ocfirst; // First objectclass for ocdiff
	char *arg_ocsecond; // Second objectclass for ocdiff
	/*
	 * Handles and internals
	 */
	const char 	*me; // Program name
	LDAP		*ld;
	struct berval  pw; // Password
	struct berval *scred; // UNUSED: Server credentials
	class_list_t *ocl; // Object Class List
	attr_list_t	*atl; // Attribute list
	attr_dfn_list_t *adl; // Attribute definition list
	char		*fname; // file name
	char		*fhash; // Hash of file being edited
	/*
	 * For ocdiff
	 */
	attr_list_t	*atl_first; // Attribute list of the first objectclass
	attr_list_t *atl_second; // Attribute list of the second objectclass
};
typedef struct runtime_ runtime_t;

/*
 * Readibility
 */
#define STR_EQ(__a, __b) ( !strcmp((__a), (__b)) )
#define STRCASE_EQ(__a, __b) ( !strcasecmp((__a), (__b)) )

/*
 * Auto-exit allocations and similar
 */
#define STRDUP(__to, __from) do { \
	if( ((__to) = strdup((__from))) == NULL ) { \
		err(EX_OSERR, "Failed to copy %zu bytes", strlen((__from))); \
	} \
} while(0);

/*
 * Logging macros
 */
#define LOG(__ctx, __lvl, ...) do { \
	if( __lvl <= (__ctx)->opt_verbose ) { \
		warnx(__VA_ARGS__); \
	} \
} while(0);
#define TRACEIN(__ctx, __fn, ...) do { \
	LOG(__ctx, 2, ">>> Entering %s", __fn); \
	LOG(__ctx, 2, "    " __VA_ARGS__); \
} while(0);
#define TRACEOUT(__ctx, __fn, ...) do { \
	LOG(__ctx, 2, "    " __VA_ARGS__); \
	LOG(__ctx, 2, "<<< Exiting  %s", __fn); \
} while(0);

/*
 * Miscellanious macros
 */
#define ATTR_IS_OC(__attr) (strcasecmp(__attr, "objectClass") == 0)
#endif // header end
